<?php
/**
 * 允许以补丁的形式添加一些功能
 */
class Item
{
    public $id="";
    public function setId($id)
    {
        $this->id = $id;
        return $this;
    }
    public function say()
    {
        echo $this->id ."\r\n";
    }
}

class ItemList
{
    /** @var Item[] $list */
    public $list=[];
    /** @param Item $item */
    public function insert($item)
    {
        $id=md5(json_encode($this->list));
        $this->list[]=$item->setId($id);
    }
    public function call()
    {
        foreach($this->list as $item){
            $item->say();
        }
    }
}

class PatchItem
{
    public $entity=null;
    public $patchs=[];
    public function __construct($entity=null,$patchs=[])
    {
        $this->entity=$entity;
        foreach($patchs as $patch){
            $this->patchs[] = $patch->setEntity($this);
        }
        $this->patchs=$patchs;
    }
    public function __call($name, $arguments)
    {
        $count = count($this->patchs);
        for($i = $count -1; $i>=0; $i--){
            $patch=$this->patchs[$i];
            if(method_exists($patch,$name)){
                $result = call_user_func_array([$patch,$name],$arguments);
                return $result === $patch ? $this : $result;
            }
        }
        $result = call_user_func_array([$this->entity,$name],$arguments);
        return $result === $this->entity ? $this : $result;
    }
    public function __get($name)
    {
        return $this->entity->$name;
    }
}

class Patch
{
    public $entity=null;
    public function setEntity($entity)
    {
        $this->entity=$entity;
        return $this;
    }
    public function __get($name)
    {
        return $this->entity->$name;
    }
    public function say()
    {
        echo "this is " . $this->id ."\r\n";
    }
}

header('Content-Type: text/plain');

$list=new ItemList;
$list->insert(new Item);
$list->insert(new PatchItem(new Item,[new Patch]));
$list->call();
